package com.basker.pisces.core.serialize.xml;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;

import com.basker.pisces.core.ISupportSort;
import com.basker.pisces.core.meta.ICollectionField;
import com.basker.pisces.core.meta.IDataField;
import com.basker.pisces.core.meta.IDataObjectField;
import com.basker.pisces.core.meta.IDataObjectMeta;
import com.basker.pisces.core.meta.IField;
import com.basker.pisces.core.meta.IReferenceField;
import com.basker.pisces.core.utils.ConvertUtils;

/**
 * XmlReader,负责将xml反序列化成对象
 *
 * @author hangwen
 */
class DataContractXmlReader {

    private Document xmlDoc;
    private IDataContractXmlSerializeHandler serializerHandler;

    public DataContractXmlReader(Document xmlDocl) {
        this.xmlDoc = xmlDocl;
    }

    public Object read() {
        return this.read(null);
    }

    public Object read(Object dataObject) {
        return readXmlElement(xmlDoc.getRootElement(), dataObject);
    }

    public void setSerializeHandler(IDataContractXmlSerializeHandler serializerHandler) {
        this.serializerHandler = serializerHandler;
    }

    private Object createDataContract(IDataObjectMeta metaIfno) {
        return metaIfno.createDataObject();
    }

    /**
     * 通过XmlElement获取对应IDataObjectMeta
     *
     * @param root dom对象
     * @return
     */
    private IDataObjectMeta getDataContractMeta(Element root) {
        Map<String, String> attrs = null;
        @SuppressWarnings("rawtypes")
        Iterator it = root.attributeIterator();
        while (it.hasNext()) {
            if (attrs == null) {
                attrs = new HashMap<String, String>(8);
            }

            Attribute att = (Attribute) it.next();
            attrs.put(att.getName(), att.getValue());
        }

        if (attrs == null) {
            attrs = Collections.emptyMap();
        }

        return serializerHandler.getDataObjectMeta(root.getName(), attrs);
    }

    /**
     * 更新当前对象集合属性值
     *
     * @param dataObject  当前对象
     * @param propElement 当前dom对象中多个相同元素片段
     * @param field       当前操作集合成员对象
     */
    private void readCollectionField(Object dataObject, Element propElement, IField field) {
        @SuppressWarnings("unchecked")
        Collection<Object> coll = (Collection<Object>) field.getValue(dataObject);
        if (coll == null) {
            coll = new ArrayList<>();
            field.setValue(dataObject, coll);
        }

        Iterator<?> itItem = propElement.elementIterator();
        while (itItem.hasNext()) {
            Element itemElement = (Element) itItem.next();

            Object item = readXmlElement(itemElement, null);
            if (item != null) {
                coll.add(item);
            }
        }

        this.sortCollection(coll);

    }

    /**
     * 反序列化对象
     *
     * @param xmlElement
     * @param dataObject 如果为null，则返回一个新创建的对象，否则返回此对象
     * @return
     */
    private Object readXmlElement(Element xmlElement, Object dataObject) {
        IDataObjectMeta dataContractMeta = this.getDataContractMeta(xmlElement);
        if (dataContractMeta == null) {
            return null;
        }

        if (dataObject == null) {
            dataObject = this.createDataContract(dataContractMeta);
        }

        setPropertys(xmlElement, dataObject, dataContractMeta);

        return dataObject;
    }

    /**
     * 设置属性
     *
     * @param objectXmlElement
     * @param dataObject
     * @param dataObjectMeta
     */
    private void setPropertys(Element objectXmlElement, Object dataObject, IDataObjectMeta dataObjectMeta) {
        @SuppressWarnings("rawtypes")
        Iterator it = objectXmlElement.elementIterator();

        while (it.hasNext()) {
            Element propElement = (Element) it.next();
            String fieldName = propElement.getName();

            IField field = dataObjectMeta.getField(fieldName);
            if (field == null) {
                continue;
            }

            if (field instanceof IDataField) {
                IDataField dataField = (IDataField) field;
                String elementValue = propElement.getTextTrim();
                Object value = null;

                if (dataField.isCData()) {
                    value = elementValue;
                } else {
                    value = ConvertUtils.convert(elementValue, dataField.getFieldClass());
                }

                dataField.setValue(dataObject, value);

            } else if (field instanceof IDataObjectField) {
                if (field instanceof IReferenceField) {
                    // 引用类型
                    continue;
                }

                List<?> elements = propElement.elements();
                if (elements.size() > 0) {
                    Element xmlElement = (Element) elements.get(0);

                    Object value = readXmlElement(xmlElement, null);

                    field.setValue(dataObject, value);
                }
            } else if (field instanceof ICollectionField) {
                readCollectionField(dataObject, propElement, field);
            }
        }
    }

    private void sortCollection(Collection<Object> coll) {
        if (coll instanceof List<?>) {
            Collections.sort((List<?>) coll, new Comparator<Object>() {

                @Override
                public int compare(Object o1, Object o2) {
                    if (o1 instanceof ISupportSort && o2 instanceof ISupportSort) {
                        Integer or1 = ((ISupportSort) o1).getSort();
                        Integer or2 = ((ISupportSort) o2).getSort();

                        if (or1 != null && or2 != null) {
                            return or1.compareTo(or2);
                        }
                    }

                    return 0;
                }
            });
        }

    }
}
